/*
	File:	video/CollisionShapeManager.hpp
	Date:	2013-06-01
	Author:	Asteroth
*/


#ifndef __ZEN_COLLISION_SHAPE_MANAGER__
#define __ZEN_COLLISION_SHAPE_MANAGER__

#include <string.h>
#include <map>

#include <BulletCollision/CollisionShapes/btShapeHull.h>

#include "../defines.hpp"

namespace zen {

	namespace video {

		class CollisionShapeManager;

		typedef ptr(btCollisionShape) PCollisionShape;
		typedef ptr(CollisionShapeManager) PCollisionShapeManager;

		class CollisionShapeManager {

		public:

			typedef std::map<std::string, PCollisionShape> PCollisionShapeMap;
			typedef std::map<std::string, PCollisionShape>::iterator PCollisionShapeMapIterator;
			typedef std::map<std::string, PCollisionShape>::const_iterator PCollisionShapeMapConstIterator;
			typedef std::pair<std::string, PCollisionShape> PCollisionShapeMapEntry;

			/**
			 * Get shape by id.
			 * @return The pointer to the specified model.
			 */
			PCollisionShape getShape(const std::string &name) const;

			/**
			 * Checks if a shape with the specified id exists.
			 */
			bool hasShape(const std::string &name) const;

			/**
			 * Replaces the shape for the specified id.
			 */
			void resetShape(const std::string &name, PCollisionShape shape);

			/**
			 * Adds a shape with a specified id only if there is no other shape with the same id.
			 */
			void addShape(const std::string &name, PCollisionShape shape);

			/**
			 * Removes all shapes from the cache, the references used across the application
			 * still remain valid.
			 */
			void clear() { shapes.clear(); }

			/**
			 * Loads a shape from file, if the shape is already loaded the cached shape will
			 * be returned instead of loading again, uses the file name as id.
			 * @param fileName	path to the file to be loaded, this parameter is also used
			 * 					as unique id for the shape.
			 * @param model		the model to be used if vertex data is required.
			 * @return The pointer to the loaded shape.
			 */
			PCollisionShape loadFile(const std::string &fileName, PModel model);

			/**
			 * Loads a shape from file, if the shape is already loaded the cached shape will
			 * be returned instead of loading again.
			 * @param			id An unique id for the shape.
			 * @param			fileName path to the file to be loaded.
			 * @param model		the model to be used if vertex data is required.
			 * @return The pointer to the loaded shape.
			 */
			PCollisionShape loadFile(const std::string &id, const std::string &fileName, PModel model);

			/**
			 * Loads a shape from jsl node, if the shape is already loaded the cached shape will
			 * be returned instead of loading again.
			 * @param id		An unique id for the shape.
			 * @param fileName	path to the file to be loaded.
			 * @param model		the model to be used if vertex data is required.
			 * @return The pointer to the loaded shape.
			 */
			PCollisionShape loadNode(const std::string &id, const jsl::Node* node, PModel model);
			

		private:

			PCollisionShapeMap shapes;

			/**
			 * Creates a shape from JSL node and model (model is needed only if the
			 * shape contains parts created from vertex data).
			 */
			inline btCollisionShape* createFromJSL(const jsl::Node* node, zen::video::Model* model = NULL);

		};


		inline PCollisionShape CollisionShapeManager::getShape(const std::string &name) const {
			PCollisionShapeMapConstIterator iter = shapes.find(name);
			return iter != shapes.end() && iter->second.get() != nullptr ? iter->second : PCollisionShape();
		}

		inline bool CollisionShapeManager::hasShape(const std::string &name) const {
			PCollisionShapeMapConstIterator iter = shapes.find(name);
			return iter != shapes.end() && iter->second.get() != nullptr ;
		}

		inline void CollisionShapeManager::resetShape(const std::string &name, PCollisionShape shape) {
			shapes.insert(PCollisionShapeMapEntry(name, shape));
		}

		inline void CollisionShapeManager::addShape(const std::string &name, PCollisionShape shape) {
			PCollisionShapeMapConstIterator iter = shapes.find(name);
			if (iter == shapes.end())
				shapes.insert(PCollisionShapeMapEntry(name, shape));
		}


	} // namespace video

} // namespace zen

#endif // __ZEN_COLLISION_SHAPE_MANAGER__
